package com.usefullc.crawler.service;

import com.alibaba.fastjson.JSONObject;
import com.usefullc.common.enums.YesNoEnum;
import com.usefullc.crawler.constants.CrawlerConstants;
import com.usefullc.crawler.domain.Active;
import com.usefullc.crawler.domain.ActiveInstance;
import com.usefullc.crawler.domain.Template;
import com.usefullc.crawler.enums.ProcessStatusEnum;
import com.usefullc.crawler.enums.RequestResultErrorStatusEnum;
import com.usefullc.crawler.selenium.CrawlerWebDriver;
import com.usefullc.crawler.selenium.CrawlerWebDriverBuilder3;
import com.usefullc.crawler.selenium.CrawlerWebDriverParam;
import com.usefullc.crawler.task.TaskRequestResult;
import com.usefullc.system.service.AbstractService;
import com.usefullc.system.service.DataConfigService;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.openqa.selenium.By;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

//import com.usefullc.crawler.selenium.CrawlerWebDriverBuilder;

/**
 * @author: Sampson
 * @date: 2022-03-29 16:07
 */
@Service
public class SeleniumRequestService extends AbstractService {

    @Autowired
    private ActiveInstanceService activeInstanceService;

    @Autowired
    private ActiveService activeService;

    @Autowired
    private TemplateService templateService;

    @Autowired
    private CrawlerWebDriverBuilder3 crawlerWebDriverBuilder3;

    @Autowired
    private DataConfigService dataConfigService;

    @Autowired
    private ActiveProcessService activeProcessService;

    private TaskRequestResult extendExecute(ActiveInstance activeInstance, WebDriver webDriver, String url){
        TaskRequestResult taskRequestResult = new TaskRequestResult();
        taskRequestResult.setSuccess(false);
        Active active = activeService.findById(activeInstance.getActiveId());
        //通用切换代理
        String timeOutExpress = dataConfigService.findByCode(CrawlerConstants.PROXY_TIME_OUT_EXPRESS).getValue();
        if (StringUtils.isNotEmpty(timeOutExpress)) {
            Object jsBanResult = crawlerWebDriverBuilder3.executeScript(webDriver, timeOutExpress);
            if (jsBanResult != null && jsBanResult.toString().equalsIgnoreCase("true")) {
                activeInstance.setStatus(ProcessStatusEnum.PAUSED.getCode());
                activeInstance.setErrContent("proxy error");
                taskRequestResult.setErrorStatus(RequestResultErrorStatusEnum.PROXY_ERROR.getCode());
                logger.error("common proxy error happened! activeInstanceId={},url={}", activeInstance.getId(), url);
                return taskRequestResult;
            }
        }

        //定义中的切换代理
        String switchProxyExpress = active.getSwitchProxyExpress();
        if (StringUtils.isNotEmpty(switchProxyExpress)) {
            Object jsBanResult = crawlerWebDriverBuilder3.executeScript(webDriver, switchProxyExpress);
            if (jsBanResult != null && jsBanResult.toString().equalsIgnoreCase("true")) {
                activeInstance.setStatus(ProcessStatusEnum.PAUSED.getCode());
                activeInstance.setErrContent("proxy error");
                taskRequestResult.setErrorStatus(RequestResultErrorStatusEnum.PROXY_ERROR.getCode());
                logger.error("private proxy error happened! activeInstanceId={},url={}", activeInstance.getId(), url);
                return taskRequestResult;
            }
        }

        //是否被屏蔽
        String analyseBanExpress = active.getAnalyseBanExpress();
        if (StringUtils.isNotEmpty(analyseBanExpress)) {
            Object jsBanResult = crawlerWebDriverBuilder3.executeScript(webDriver, analyseBanExpress);
            if (jsBanResult != null && jsBanResult.toString().equalsIgnoreCase("true")) {
                activeInstance.setStatus(ProcessStatusEnum.PAUSED.getCode());
                activeInstance.setErrContent("ban error");
                taskRequestResult.setErrorStatus(RequestResultErrorStatusEnum.BAN.getCode());
                logger.error("ban happened! activeInstanceId={},url={}", activeInstance.getId(), url);
                return taskRequestResult;
            }
        }
        taskRequestResult.setSuccess(true);
        return taskRequestResult;
    }

    public TaskRequestResult execute(Long activeInstanceId) {
        ActiveInstance activeInstance = this.activeInstanceService.findById(activeInstanceId);
        if(activeInstance == null){
            logger.error("error");
        }
//        long startTime = System.currentTimeMillis();
        TaskRequestResult taskRequestResult = new TaskRequestResult();
//        taskRequestResult.setErrorStatus(RequestResultErrorStatusEnum.OTHER.getCode());
        taskRequestResult.setSuccess(false);
        CrawlerWebDriver crawlerWebDriver = null;
        try {
            String url = activeInstance.getUrl();
            Active active = activeService.findById(activeInstance.getActiveId());
            Template template = templateService.findById(active.getTemplateId());
            CrawlerWebDriverParam param = new CrawlerWebDriverParam();
            param.setActiveInstanceId(activeInstance.getId());
            param.setEnableProxy(template.getEnableProxy());
            param.setEnableImage(template.getEnableImage());
            param.setEnableJavascript(template.getEnableJavascript());
            param.setEnableStyle(template.getEnableStyle());
            param.setTimeRdMs(template.getRunRdMs());
            param.setWebDriverType(active.getWebDriverType());
            param.setCookie(active.getCookie());
            crawlerWebDriver = crawlerWebDriverBuilder3.open(url, param);
//            logger.info("crawlerWebDriver={},url={}", crawlerWebDriver, url);
            WebDriver webDriver = crawlerWebDriver.getWebDriver();


            taskRequestResult = this.extendExecute(activeInstance, webDriver, url);
            if(!taskRequestResult.isSuccess()){
                return taskRequestResult;
            }

            //页面加载超时等待
            try{
                String waitCssSelectorExpress = active.getWaitCssSelectorExpress();
                if (StringUtils.isNotEmpty(waitCssSelectorExpress)) {
                    WebDriverWait wait = new WebDriverWait(webDriver, 15);
                    wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector(waitCssSelectorExpress)));
                }
            }catch (Exception e) {
                //执行下扩展
                taskRequestResult = this.extendExecute(activeInstance, webDriver, url);
                if (!taskRequestResult.isSuccess()) {
                    return taskRequestResult;
                }
            }


            //存储页面源码
            if (template.getStorePageSource() == YesNoEnum.YES.getCode()) {
                String pageSource = webDriver.getPageSource();
                activeInstance.setResponseBody(pageSource);
            }

            //解析目标内容
            String analyseExpress = active.getAnalyseExpress();
            Object jsResult;
            try {
                jsResult = crawlerWebDriverBuilder3.executeScript(webDriver, analyseExpress);
            } catch (Exception e) {
                logger.error("executeScript error",e);
                //执行下扩展
                taskRequestResult = this.extendExecute(activeInstance, webDriver, url);
                if(!taskRequestResult.isSuccess()){
                    return taskRequestResult;
                }else{
                    //脚本报错，暂时直接ban,暂停流程
                    logger.info("local script error,ban happened,activeInstanceId={}",activeInstance.getId());
                    activeInstance.setStatus(ProcessStatusEnum.PAUSED.getCode());
                    activeInstance.setErrContent(ExceptionUtils.getStackTrace(e));
                    taskRequestResult.setErrorStatus(RequestResultErrorStatusEnum.BAN.getCode());
                    return taskRequestResult;
                }
            }
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("data", jsResult);
            activeInstance.setResponseAnalyseBody(jsonObject.toJSONString());
            activeInstance.setStatus(ProcessStatusEnum.FINISHED.getCode());
//            activeInstance.setResponseRawHeader(webDriver.get);

        } catch (Exception e) {
            if (StringUtils.contains(e.getMessage(), "ERR_PROXY_CONNECTION_FAILED")) {
                taskRequestResult.setErrorStatus(RequestResultErrorStatusEnum.PROXY_ERROR.getCode());
            } else {
                taskRequestResult.setErrorStatus(RequestResultErrorStatusEnum.OTHER.getCode());
            }
            if(activeInstance == null){
                logger.error("error");
            }
            activeInstance.setStatus(ProcessStatusEnum.PAUSED.getCode());
            activeInstance.setErrContent(ExceptionUtils.getStackTrace(e));
            logger.error("selenium execute failed", e);
        } finally {
            if(activeInstance == null){
                logger.error("error");
            }
            taskRequestResult.setSuccess(activeInstance.getStatus() == ProcessStatusEnum.FINISHED.getCode());
            taskRequestResult.setActiveInstance(activeInstance);
            taskRequestResult.setCrawlerWebDriver(crawlerWebDriver);

//            try{
//
//
//            }catch (Exception e){
//                taskRequestResult.setErrorStatus(RequestResultErrorStatusEnum.BAN.getCode());
//                taskRequestResult.setSuccess(false);
//               logger.error("rewrite activeInstance failed,ban happened",e);
//            }
        }
        return taskRequestResult;
    }
}
